#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <iostream>

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    labSocketState = new QLabel("socket 状态：");
    labSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(labSocketState);
    QString localIPv4 = this->getLocalIPv4(); // 获取本机 IP 地址
    this->setWindowTitle(this->windowTitle() + localIPv4);
    ui->comboTargetIP->addItem(localIPv4);

    udpSocket = new QUdpSocket(this); // 创建 socket

    connect(udpSocket, &QUdpSocket::stateChanged, this, &MainWindow::do_socketStateChanged);
    do_socketStateChanged(udpSocket->state()); // 运行一次，显示当前状态
    connect(udpSocket, &QUdpSocket::readyRead, this, &MainWindow::do_socketReadyRead);

    // “绑定端口”按钮
    connect(ui->actStart, &QAction::triggered, this, [this]() {
        uint16_t port = ui->spinBindPort->value(); // 本机 UDP 端口
        //绑定 允许多个进程/线程绑定到同一个 IP 和端口，用于接收广播或多播
        if (udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint))
        {
            ui->textEdit->appendPlainText("**已成功绑定");
            ui->textEdit->appendPlainText("**绑定端口：" + QString::number(udpSocket->localPort()));
            ui->actStart->setEnabled(false);
            ui->actStop->setEnabled(true);
            ui->btnSend->setEnabled(true);
            ui->btnBroadcast->setEnabled(true);
        }
        else
        {
            ui->textEdit->appendPlainText("**绑定失败");
        }
    });

    // “解除绑定”按钮
    connect(ui->actStop, &QAction::triggered, this, [this]() {
        udpSocket->abort(); // 解除绑定，复位 socket
        ui->actStart->setEnabled(true);
        ui->actStop->setEnabled(false);
        ui->btnSend->setEnabled(false);
        ui->btnBroadcast->setEnabled(false);
        ui->textEdit->appendPlainText("**已解除绑定");
    });

    //"发送消息" 按钮
    connect(ui->btnSend, &QPushButton::clicked, this, [this]() {
        QString targetIPv4 = ui->comboTargetIP->currentText(); // 目标 IP 地址
        QHostAddress targetAddress(targetIPv4);                // 目标主机
        uint16_t targetPort = ui->spinTargetPort->value();     // 目标端口
        QString msg = ui->editMsg->text();                     // 发送的消息内容
        QByteArray theData = msg.toUtf8();
        // 向一个目标用户发送消息时，需要指定目标 IP 地址和目标端口。
        udpSocket->writeDatagram(theData, targetAddress, targetPort); // 发出数据报
        ui->textEdit->appendPlainText("[out] " + msg);
        ui->editMsg->clear();
        ui->editMsg->setFocus();
    });

    // “广播消息”按钮
    connect(ui->btnBroadcast, &QPushButton::clicked, this, [this]() {
        uint16_t targetPort = ui->spinTargetPort->value(); // 目标端口
        QString msg = ui->editMsg->text();                 // 发送的消息内容
        QByteArray theData = msg.toUtf8();
        // 在广播消息时，只需将目标地址更换为一个特殊地址，即广播地址 QHostAddress::Broadcast，这个地址一般是 255.255.255.255。
        udpSocket->writeDatagram(theData, QHostAddress::Broadcast, targetPort); // 发出数据报
        ui->textEdit->appendPlainText("[broadcast] " + msg);
        ui->editMsg->clear();
        ui->editMsg->setFocus();
    });
}

MainWindow::~MainWindow()
{
    if(udpSocket != nullptr)
    {

        udpSocket->abort(); // 解除绑定，复位 socket
    }
    delete ui;
}

void MainWindow::do_socketStateChanged(QAbstractSocket::SocketState socketState)
{
    qDebug() << "do_socketStateChanged";
    QString state = "";
    switch (socketState)
    {
    case QAbstractSocket::SocketState::UnconnectedState:
        state = "UnconnectedState";
        break;
    case QAbstractSocket::SocketState::HostLookupState:
        state = "HostLookupState";
        break;
    case QAbstractSocket::SocketState::ConnectingState:
        state = "ConnectingState";
        break;
    case QAbstractSocket::SocketState::ConnectedState:
        state = "ConnectedState";
        break;
    case QAbstractSocket::SocketState::BoundState:
        state = "BoundState";
        break;
    case QAbstractSocket::SocketState::ListeningState:
        state = "ListeningState";
        break;
    case QAbstractSocket::SocketState::ClosingState:
        state = "ClosingState";
        break;
    default:
        break;
    }
    labSocketState->setText(state);
}

QString MainWindow::getLocalIPv4()
{
    QString hostName = QHostInfo::localHostName(); // 本机主机名
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIPv4 = "";
    QList<QHostAddress> addrList = hostInfo.addresses(); // 本机 IP 地址列表
    if (addrList.isEmpty())
        return localIPv4;
    for (const auto& aHost : addrList)
    {
        if (aHost.protocol() == QAbstractSocket::IPv4Protocol)
        {
            localIPv4 = aHost.toString();
            break;
        }
    }
    return localIPv4;
}

void MainWindow::do_socketReadyRead()
{
    while (udpSocket->hasPendingDatagrams()) // 是否有待读取的数据报
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize()); // 待读取的数据报的字节数
        QHostAddress peerAddress;
        uint16_t peerPort;
        udpSocket->readDatagram(datagram.data(), datagram.size(), &peerAddress, &peerPort);
        QString str = datagram.data();
        QString peer = "[From " + peerAddress.toString() + ":" + QString::number(peerPort) + "]";
        ui->textEdit->appendPlainText(peer + str);
    }
}
